1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 module hip.util.array;
12 private import hip.util.conv : to;
13 
14 /**
15 * Uses accessor on the array to find an element
16 */
17 int indexOf(string accessor, T, Q)(T[] arr, Q element, int startIndex = 0)
18 {
19     static if(accessor != "")
20         enum op = "."~accessor;
21     else
22         enum op = accessor;
23     const size_t len = arr.length;
24     for(size_t i = startIndex; i < len; i++)
25         mixin("if(arr[i]"~op~" == element)return cast(int)i;");
26     return -1;
27 }
28 /**
29 * Returns index of element if it finds or returns -1 if not
30 */
31 int indexOf(T)(in T[] arr, T element, int startIndex = 0) pure nothrow @nogc
32 {
33     if(startIndex < 0)
34         return -1;
35     for(int i = startIndex; i < arr.length; i++)
36         if(arr[i] == element)
37             return i;
38     return -1;
39 }
40 
41 import std.typecons: isTuple;
42 ///Index of for tuples
43 int indexOf(T, V)(in T tuple, V value) pure nothrow @nogc if(isTuple!T)
44 {
45     foreach(i, v; tuple)
46     {
47         static if(is(typeof(v) == V))
48         if(v == value)
49             return i;
50     }
51     return -1;
52 }
53 
54 
55 
56 int lastIndexOf(T)(T[] arr, T element, int startIndex = -1)
57 {
58     const size_t len = arr.length;
59     if(len==0)return-1;
60     if(startIndex < 0) startIndex = (cast(int)len - 1);
61     for(int i = startIndex; i >= 0; i--)
62         if(arr[i] == element)
63             return i;
64     return -1;
65 }
66 
67 /**
68 *   Should work only for numerics
69 */
70 int binarySearch(T)(in T[] arr, T element) @nogc @safe nothrow
71 {
72     uint l = 0;
73     uint r = arr.length;
74     uint m;
75     while(l <= r)
76     {
77         m = cast(uint)((l+r)/2);
78         if(arr[m] < element)
79             l = m + 1;
80         else if(arr[m] > element)
81             r = m - 1;
82         else if(arr[m] == element)
83             return m;
84     }
85 
86     return -1;
87 }
88 
89 bool swapAt(T)(T[] arr, int index1, int index2) @nogc @safe nothrow
90 {
91     if(index1 == index2 || index1 < 0 || index1 >= arr.length || index2 < 0 || index2 >= arr.length)
92         return false;
93     T temp  = arr[index1];
94     arr[index1] = arr[index2];
95     arr[index2] = temp;
96     return true;
97 }
98 
99 /**
100 *  Returns if swap was succesful
101 */
102 bool swapElementsFromArray(T)(T[] arr, T element1, T element2) @nogc @safe nothrow
103 {
104     long index1 = arr.indexOf(element1);
105     long index2 = arr.indexOf(element2);
106 
107     if(index1 != -1 && index2 != 1)
108     {
109         T temp = arr[index1];
110         arr[index1] = arr[index2];
111         arr[index2] = temp;
112         return true;
113     }
114     return false;
115 }
116 
117 
118 bool popFront(T)(ref T[] arr, out T val)
119 {
120     import hip.util.memory;
121     if(arr.length == 0)
122         return false;
123     val = arr[0];
124     memcpy(arr.ptr, arr.ptr+1, (cast(int)arr.length-1)*T.sizeof);
125     arr.length--;
126     return true;
127 }
128 bool popFront(T)(ref T[] arr)
129 {
130     T val;
131     return popFront(arr, val);
132 }
133 bool remove(T)(ref T[] arr, T val)
134 {
135     for(size_t i = 0; i < arr.length; i++)
136     {
137         if(arr[i] == val)
138         {
139             for(size_t z = 0; z+i < cast(int)arr.length-1; z++)
140                 arr[z+i] = arr[z+i+1];
141             arr.length--;
142             return true;
143         }
144     }
145     return false;
146 }
147 
148 bool remove(T)(ref T[] arr, const(T)* val)
149 {
150     for(size_t i = 0; i < arr.length; i++)
151     {
152         if(&arr[i] == val)
153         {
154             for(size_t z = 0; z+i < cast(int)arr.length-1; z++)
155                 arr[z+i] = arr[z+i+1];
156             arr.length--;
157             return true;
158         }
159     }
160     return false;
161 }
162 
163 pragma(inline, true)
164 bool contains(T)(in T[] arr, T val) pure nothrow @nogc {return arr.indexOf(val) != -1;} 
165 
166 pragma(inline, true)
167 bool contains(T, V)(in T[] tuple, V val) pure nothrow @nogc {return tuple.indexOf(val) != -1;} 
168 
169 
170 /**
171 *   Compare a array of structures member with a target value
172 */
173 bool contains(string accessor, T, Q)(ref T[] arr, Q val)
174 {
175     for(size_t i = 0; i < arr.length; i++)
176     {
177         if(__traits(getMember, arr[i], accessor) == val)
178             return true;
179     }
180     return false;
181 }
182 
183 /**
184 *   Compare two different structures accessing different members
185 */
186 bool contains(string accessorA, string accessorB, T, Q)(ref T[] arr, Q val)
187 {
188     for(size_t i = 0; i < arr.length; i++)
189     {
190         if(__traits(getMember, arr[i], accessorA) == __traits(getMember, val, accessorB))
191             return true;
192     }
193     return false;
194 }
195 
196 pragma(inline, true) bool isEmpty(T)(in T[] arr){return arr.length == 0;}
197 
198 
199 import std.traits:ForeachType;
200 ForeachType!(T)[] array(T)(T range)
201 {
202     typeof(return) ret;
203     foreach(r;range)
204         ret~= r;
205     return ret;
206 }
207 
208 string join(T)(T[] arr, string separator = "")
209 {
210     import hip.util.conv;
211     string ret;
212     if(arr.length == 0) return "";
213 
214     ret = toString(arr[0]);
215     for(int i = 1; i < arr.length; i++)
216     {
217         ret~= separator;
218         ret~= arr[i];
219     }
220     return ret;
221 }
222 
223 string join(T)(T[] arr, char separator)
224 {
225     char[1] temp = separator;
226     return join(arr, cast(string)temp);
227 }
228 
229 
230 void printArrayWithoutValues(T)(const T[] arr, T[] ignoreValues...)
231 {
232     import hip.console.log;
233     string str = "[";
234     MainLoop: foreach (val; arr)
235     {
236         foreach (arg; ignoreValues)
237             if(val == arg) //Ignore if value is in the loop list
238                 continue MainLoop;
239         str~= to!string(val) ~", ";
240     }
241     str~= "]";
242     const int index = lastIndexOf(str, ',');
243     if(index == -1)
244         logln("[]");
245     else
246         logln(str[0..index] ~ str[index+2..$]);
247 }
248 
249 unittest
250 {
251     assert(indexOf([2, 3, 4], 3) == 1);
252     assert(swapElementsFromArray([5, 10, 9], 10, 9));
253     assert(lastIndexOf([2, 3, 3, 4], 4) == 3);
254 }